package algorithm.aStart_8number;

import java.awt.Point;
import java.util.Comparator;

import library.Tracer;
import library.string.Ran;

class Node implements Comparator<Node> {
	private static final int ALPHA = 1;
	private static final int BETA = 1;
	private String[][] board;

	/**
	 * for being used as Comparator
	 */
	public Node(String name) {
		this.name = name;
	}

	public Node(Node node) {
		if (node == null)
			return;
		this.currentCost = node.currentCost;
		this.heuristic = node.heuristic;
		this.test = node.test;
		int n = node.board.length;
		this.board = new String[n][];
		for (int i = 0; i < board.length; i++) {
			board[i] = new String[n];
			for (int j = 0; j < board[i].length; j++) {
				board[i][j] = node.board[i][j];
			}
		}
	}

	public Node(int currentCost, int n, String[] strings) {
		test = strings.clone();
		Ran r = new Ran();
		r.disruptRoder(strings);
		this.heuristic = 0;
		this.currentCost = currentCost;
		board = new String[n][];
		for (int i = 0; i < board.length; i++) {
			board[i] = new String[n];
			for (int j = 0; j < board[i].length; j++) {
				board[i][j] = strings[i * n + j];
			}
		}
		initHeuristic();
	}

	public boolean isBoardEquals(Node node) {
		String[][] board = node.board;
		for (int i = 0; i < board.length; i++)
			for (int j = 0; j < board[i].length; j++)
				if (!this.board[i][j].equals(board[i][j]))
					return false;
		return true;
	}

	private String[] test;
	public int heuristic, currentCost;
	public Node pred;

	/**
	 * i stand for the direction which '#' will be swapped to
	 * 
	 * 0: swap up. 1: swap down. 2: swap left. 3: swap right.
	 * 
	 * @param i
	 * @return
	 */
	public boolean swapTo(int direction) {
		Point p = find_Blank_Point();
		if (!canSwap(direction, p))
			return false;

		String tmp;
		switch (direction) {
		case 0:// up
			tmp = board[p.y - 1][p.x];
			board[p.y - 1][p.x] = board[p.y][p.x];
			board[p.y][p.x] = tmp;
			break;
		case 1:// down
			tmp = board[p.y + 1][p.x];
			board[p.y + 1][p.x] = board[p.y][p.x];
			board[p.y][p.x] = tmp;
			break;
		case 2:// left
			tmp = board[p.y][p.x - 1];
			board[p.y][p.x - 1] = board[p.y][p.x];
			board[p.y][p.x] = tmp;
			break;
		case 3:// right
			tmp = board[p.y][p.x + 1];
			board[p.y][p.x + 1] = board[p.y][p.x];
			board[p.y][p.x] = tmp;
			break;
		default:
			return false;
		}
		currentCost++;
		initHeuristic();
		return true;
	}

	private Point find_Blank_Point() {
		for (int i = 0; i < board.length; i++)
			for (int j = 0; j < board.length; j++)
				if (board[i][j] == "#") {
					return new Point(j, i);
				}
		return null;
	}

	private boolean canSwap(int direction, Point p) {
		int lastIndex = board.length - 1;
		switch (direction) {
		case 0:// up
			if (p.y == 0)
				return false;
			break;
		case 1:// down
			if (p.y == lastIndex)
				return false;
			break;
		case 2:// left
			if (p.x == 0)
				return false;
			break;
		case 3:// right
			if (p.x == lastIndex)
				return false;
			break;
		default:
			return false;
		}
		return true;
	}

	private void initHeuristic() {
		heuristic = 0;
		for (int i = 0; i < board.length; i++) {
			for (int j = 0; j < board[i].length; j++) {
				if (!test[i * board.length + j].equals(board[i][j]))
					heuristic++;
			}
		}
	}

	public void disp() {
		if (!Tracer.isPrinting("scaffolding1") && !Tracer.isPrinting("size"))
			if (this.pred != null) {
				this.pred.disp();
				Tracer.splitLine("child below");
			}

		for (String bb[] : board) {
			for (String b : bb) {
				System.out.print(b + " ");
			}
			System.out.println("");
		}
		Tracer.debug(String.format("[%s] h:%d, g:%d", name, heuristic, currentCost));
	}

	public String name;

	/*
	 * if compare method returns 0, then the element cannot be added into
	 * TreeSet
	 */
	@Override
	public int compare(Node o1, Node o2) {
		int left = o1.currentCost * ALPHA + o1.heuristic * BETA;
		int right = o2.currentCost * ALPHA + o2.heuristic * BETA;
		if (left == right)
			if (!o1.isBoardEquals(o2))
				return -1;
		return 1 * (left - right);
	}
}

//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//